package com.vegetable.common.aspect;

import com.vegetable.common.annotation.ApprovalDataPermission;
import com.vegetable.common.utils.HttpContextUtils;
import com.vegetable.modules.entity.sys.SysUserEntity;
import com.vegetable.modules.entity.wx.WxDepartment;
import com.vegetable.modules.service.wx.WxDepartmentService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;

/**
 * 审批数据权限切面类
 * 实现审批数据的权限控制功能
 *
 * 业务规则：
 * 1. 财务部门（部门ID为5）：可以查看所有审批记录
 * 2. 其他部门用户：只能查看自己提交的审批记录
 * 3. 未分配部门的用户：只能查看自己提交的审批记录
 * 4. 未绑定企业微信的用户：无法查看任何审批记录
 *
 * 字段映射关系：
 * sys_user.wx_user_id = wx_approval.user_id
 *
 * @author Qoder
 * @since 2025-10-21
 */
@Slf4j
@Aspect
@Component
public class ApprovalDataPermissionAspect {
    
    @Autowired
    private WxDepartmentService wxDepartmentService;
    
    @Pointcut("@annotation(com.vegetable.common.annotation.ApprovalDataPermission)")
    public void approvalDataPermissionPointcut() {
    }
    
    @Around("approvalDataPermissionPointcut()")
    public Object doAround(ProceedingJoinPoint point) throws Throwable {
        try {
            log.info("========== 审批数据权限控制开始 ==========");
            log.info("请求路径: {}", HttpContextUtils.getHttpServletRequest().getRequestURI());
            log.info("请求方法: {}", point.getSignature().toShortString());
            
            // 获取当前用户的系统ID
            Long userId = getCurrentUserId();
            log.info("获取到的系统用户ID: {}", userId);
            
            if (userId == null) {
                log.warn("⚠️ 无法获取当前用户ID，应用默认数据权限控制（不显示任何数据）");
                log.warn("可能原因：1. 请求未经过OAuth2认证  2. Subject中没有用户信息  3. Token无效或过期");
                // 无法获取用户ID时，默认不显示任何数据
                applyDefaultNoDataFilter(point);
                return point.proceed();
            }
            
            // 获取当前用户的企业微信ID
            String wxUserId = getCurrentWxUserId();
            log.info("获取到的企业微信用户ID: {}", wxUserId);
            
            if (StringUtils.isEmpty(wxUserId)) {
                log.warn("⚠️ 用户{}未绑定企业微信账号，无法查看审批数据", userId);
                // 用户未绑定企业微信时，不显示任何数据
                applyDefaultNoDataFilter(point);
                return point.proceed();
            }
            
            // 获取方法上的注解
            MethodSignature signature = (MethodSignature) point.getSignature();
            Method method = signature.getMethod();
            ApprovalDataPermission approvalDataPermission = method.getAnnotation(ApprovalDataPermission.class);
            
            if (approvalDataPermission == null) {
                return point.proceed();
            }
            
            // 处理审批数据权限
            handleApprovalPermission(point, approvalDataPermission, userId, wxUserId);
            
            log.info("========== 审批数据权限控制结束 ==========");
            return point.proceed();
        } catch (Exception e) {
            log.error("❌ 审批数据权限控制处理异常", e);
            // 发生异常时，默认不显示任何数据，确保安全性
            applyDefaultNoDataFilter(point);
            return point.proceed();
        }
    }
    
    /**
     * 处理审批数据权限
     * 
     * @param point 切点
     * @param approvalDataPermission 注解
     * @param userId 系统用户ID
     * @param wxUserId 企业微信用户ID
     */
    private void handleApprovalPermission(ProceedingJoinPoint point, 
                                         ApprovalDataPermission approvalDataPermission, 
                                         Long userId, 
                                         String wxUserId) {
        try {
            // 获取用户所属部门
            List<WxDepartment> departments = wxDepartmentService.getSysUserDepartments(userId);
            if (CollectionUtils.isEmpty(departments)) {
                log.info("用户{}未关联任何部门，只能查看自己提交的审批", userId);
                // 用户未关联部门时，只能看自己提交的审批
                applyApprovalFilter(point, approvalDataPermission, Arrays.asList(wxUserId));
                return;
            }
            
            // 检查用户是否属于财务部门（部门ID为5）
            boolean isFinanceDepartment = departments.stream()
                    .anyMatch(dept -> dept.getId() == 5);
            
            // 财务部门可以看到全部数据，无需过滤
            if (isFinanceDepartment) {
                log.info("用户{}属于财务部门，可以查看全部审批数据", userId);
                return;
            }
            
            // 非财务部门用户只能查看自己提交的审批
            log.info("用户{}（wxUserId={}）不属于财务部门，只能查看自己提交的审批", userId, wxUserId);
            applyApprovalFilter(point, approvalDataPermission, Arrays.asList(wxUserId));
        } catch (Exception e) {
            log.error("处理审批数据权限异常", e);
            // 异常时默认只显示用户自己的数据
            applyApprovalFilter(point, approvalDataPermission, Arrays.asList(wxUserId));
        }
    }
    
    /**
     * 应用审批数据过滤
     * 
     * @param point 切点
     * @param approvalDataPermission 注解
     * @param userIds 企业微信用户ID列表
     */
    private void applyApprovalFilter(ProceedingJoinPoint point, 
                                     ApprovalDataPermission approvalDataPermission, 
                                     List<String> userIds) {
        try {
            // 获取方法参数
            Object[] args = point.getArgs();
            Class<?> filterParamClass = approvalDataPermission.filterParam();
            
            // 查找需要过滤的PO参数
            for (Object arg : args) {
                if (arg != null && filterParamClass.isAssignableFrom(arg.getClass())) {
                    // 通过反射设置userIds字段
                    try {
                        java.lang.reflect.Field userIdsField = arg.getClass().getDeclaredField("userIds");
                        userIdsField.setAccessible(true);
                        userIdsField.set(arg, userIds);
                        log.info("已为PO对象{}设置userIds过滤: {}", arg.getClass().getName(), userIds);
                    } catch (NoSuchFieldException e) {
                        log.info("PO对象{}中未找到userIds字段，无法进行数据权限过滤", arg.getClass().getName());
                    }
                }
            }
        } catch (Exception e) {
            log.error("应用审批数据过滤异常", e);
        }
    }
    
    /**
     * 应用默认的无数据过滤器
     * 确保无法获取用户ID或未绑定企业微信时不显示任何数据
     * 
     * @param point 切点
     */
    private void applyDefaultNoDataFilter(ProceedingJoinPoint point) {
        try {
            // 获取方法参数
            Object[] args = point.getArgs();
            
            // 查找需要过滤的参数（PO对象）
            for (Object arg : args) {
                if (arg != null) {
                    // 尝试处理PO对象
                    try {
                        Class<?> argClass = arg.getClass();
                        java.lang.reflect.Field userIdsField = null;
                        
                        // 尝试获取userIds字段
                        try {
                            userIdsField = argClass.getDeclaredField("userIds");
                        } catch (NoSuchFieldException e) {
                            // 如果当前类没有，尝试父类
                            try {
                                userIdsField = argClass.getSuperclass().getDeclaredField("userIds");
                            } catch (NoSuchFieldException ex) {
                                // 父类也没有，跳过
                                continue;
                            }
                        }
                        
                        if (userIdsField != null) {
                            userIdsField.setAccessible(true);
                            // 设置不存在的ID，确保查询结果为空
                            userIdsField.set(arg, Arrays.asList("-1"));
                            log.info("已为参数{}设置默认userIds过滤（不显示任何数据）", arg.getClass().getName());
                        }
                    } catch (Exception e) {
                        log.info("无法为参数{}设置默认userIds", arg.getClass().getName());
                    }
                }
            }
        } catch (Exception e) {
            log.error("应用默认无数据过滤器异常", e);
        }
    }
    
    /**
     * 获取当前用户的系统用户ID
     * 
     * @return 系统用户ID（sys_user.user_id）
     */
    private Long getCurrentUserId() {
        try {
            log.debug("开始获取当前用户ID...");
            
            // 从Shiro安全框架中获取当前用户ID
            Subject subject = SecurityUtils.getSubject();
            log.debug("Subject: {}", subject);
            
            if (subject != null) {
                Object principal = subject.getPrincipal();
                log.debug("Principal类型: {}", principal != null ? principal.getClass().getName() : "null");
                
                if (principal instanceof SysUserEntity) {
                    SysUserEntity user = (SysUserEntity) principal;
                    log.debug("从Shiro获取到用户: userId={}, username={}", user.getUserId(), user.getUsername());
                    return user.getUserId();
                }
            }
            
            // 从请求上下文中获取用户信息（备用方案）
            Object userIdObj = HttpContextUtils.getHttpServletRequest().getAttribute("userId");
            if (userIdObj != null) {
                log.debug("从请求上下文获取到userId: {}", userIdObj);
                return Long.valueOf(userIdObj.toString());
            }
            
            log.debug("未能从任何途径获取到用户ID");
        } catch (Exception e) {
            log.error("获取当前用户ID异常", e);
        }
        return null;
    }
    
    /**
     * 获取当前用户的企业微信用户ID
     * 
     * @return 企业微信用户ID（sys_user.wx_user_id）
     */
    private String getCurrentWxUserId() {
        try {
            // 从Shiro安全框架中获取当前用户
            Subject subject = SecurityUtils.getSubject();
            if (subject != null) {
                Object principal = subject.getPrincipal();
                if (principal instanceof SysUserEntity) {
                    SysUserEntity user = (SysUserEntity) principal;
                    return user.getWxUserId();
                }
            }
        } catch (Exception e) {
            log.error("获取当前用户企业微信ID异常", e);
        }
        return null;
    }
}
